﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Helpers
{
    public class VpnHelper
    {
        public VpnHelper(string serverAddress, string userName, string passWord)
           : this(serverAddress, serverAddress, userName, passWord, Protocol.SSTP)
        {

        }
        public VpnHelper(string serverAddress, string connectionName, string userName, string passWord)
            : this(serverAddress, connectionName, userName, passWord, Protocol.SSTP)
        {

        }

        public VpnHelper(string serverAddress, string connectionName, string userName, string passWord, Protocol protocol)
        {
            this.serverAddress = serverAddress;
            this.connectionName = connectionName;
            this.userName = userName;
            this.passWord = passWord;
            this.protocol = protocol;
            this.rasDialFileName = Path.Combine(WinDir, "rasdial.exe");
        }

        private static string WinDir = Environment.GetFolderPath(Environment.SpecialFolder.System);
        private string rasDialFileName;

        private readonly string serverAddress;
        private readonly string connectionName;
        private readonly string userName;
        private readonly string passWord;
        private readonly Protocol protocol;

        public bool IsActive
        {
            get
            {
                using (Process myProcess = new Process())
                {
                    myProcess.StartInfo.CreateNoWindow = true;
                    myProcess.StartInfo.UseShellExecute = false;
                    myProcess.StartInfo.RedirectStandardInput = true;
                    myProcess.StartInfo.RedirectStandardOutput = true;
                    myProcess.StartInfo.FileName = "cmd.exe";
                    myProcess.Start();
                    myProcess.StandardInput.WriteLine("ipconfig");
                    myProcess.StandardInput.WriteLine("exit");
                    myProcess.WaitForExit();

                    string content = myProcess.StandardOutput.ReadToEnd();
                    if (content.Contains("0.0.0.0"))
                    {
                        return true;
                    }

                    return false;
                }
            }
        }

        /// <summary>
        /// 切换vpn
        /// </summary>
        /// <param name="entryName"></param>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        public static bool SwitchVpn(string entryName, string userName, string password)
        {
            var vpn = new Helpers.VpnHelper(entryName, userName, password);
            try
            {
                Console.WriteLine($"{DateTime.Now}-重连中。。。");
                if (vpn.IsActive)
                {
                    if (!vpn.TryDisconnect())
                        Console.WriteLine($"{DateTime.Now}-vpn断开失败");
                }
                if (vpn.TryConnect())
                {
                    Console.WriteLine($"{DateTime.Now}-vpn重连成功");
                    return true;
                }
                else
                    Console.WriteLine($"{DateTime.Now}-vpn重连失败");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            return false;
        }

        /// <summary>
        /// 用于检查IP地址或域名是否可以使用TCP/IP协议访问(使用Ping命令),true表示Ping成功,false表示Ping失败 
        /// </summary>
        /// <param name="strIpOrDName">输入参数,表示IP地址或域名</param>
        /// <returns></returns>
        public static async Task<bool> PingIpOrDomainName(string strIpOrDName, int times)
        {
            while (times-- > 0)
            {
                try
                {
                    Ping ping = new Ping();
                    PingReply pr = ping.Send(strIpOrDName);
                    if (pr.Status == IPStatus.Success)
                    {
                        return true;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                finally
                {
                    Console.WriteLine("网络不通");
                    await Task.Delay(1000);
                }
            }
            return false;
        }

        public bool TryConnect()
        {
            try
            {
                string args = $"{connectionName} {userName} {passWord}";
                ProcessStartInfo myProcess = new ProcessStartInfo(rasDialFileName, args);
                myProcess.CreateNoWindow = true;
                myProcess.UseShellExecute = false;
                Process.Start(myProcess);
            }
            catch (Exception Ex)
            {
                Debug.Assert(false, Ex.ToString());
            }

            WaitUntilActive();
            if (IsActive)
            {
                return true;
            }

            return false;
        }

        public bool TryDisconnect()
        {
            try
            {
                string args = $@"{connectionName} /d";
                ProcessStartInfo myProcess = new ProcessStartInfo(rasDialFileName, args);
                myProcess.CreateNoWindow = true;
                myProcess.UseShellExecute = false;
                Process.Start(myProcess);
            }
            catch (Exception Ex)
            {
                Debug.Assert(false, Ex.ToString());
            }

            WaitUntilInActive();
            if (!IsActive)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 等待断开
        /// </summary>
        /// <param name="timeOut"></param>
        /// <returns></returns>
        private bool WaitUntilInActive(int timeOut = 10)
        {
            for (int i = 0; i < timeOut; i++)
            {
                if (this.IsActive)
                {
                    Thread.Sleep(1000);
                }
                else
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 等待连接
        /// </summary>
        /// <param name="timeOut"></param>
        /// <returns></returns>
        private bool WaitUntilActive(int timeOut = 10)
        {
            for (int i = 0; i < timeOut; i++)
            {
                if (!this.IsActive)
                {
                    Thread.Sleep(1000);
                }
                else
                {
                    return true;
                }
            }

            return false;
        }
    }

    public enum Protocol
    {
        SSTP,
        IKEV2,
        PPTP,
        L2TP,
    }
}
